//
// Created by yinlijun on 17-10-1.
// 连接相关工具函数
//

#include <fcntl.h>
#include "connection_utils.h"
#define LISTEN_BACKLOG 4

int socket_make_sock_addr_un(const char* name, struct sockaddr_un *p_addr, socklen_t  *alen) {
    memset(p_addr, 0, sizeof(*p_addr));
    size_t namelen = strlen(name);
    if(namelen + 1 > sizeof(p_addr->sun_path)) {
        return -1;
    }
    p_addr->sun_path[0] = 0;
    memcpy(p_addr->sun_path + 1, name, namelen);
    p_addr->sun_family = AF_LOCAL;
    *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
    return 0;
}

int set_non_block(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    if(flags < 0) {
        return -1;
    }
    int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
    if(r < 0) {
        return -1;
    }
    return 0;
}

int socket_local_server_bind(int s, const char* name) {
    struct sockaddr_un addr;
    socklen_t alen;
    int n;
    int err;

    err = socket_make_sock_addr_un(name, &addr, &alen);
    unlink(addr.sun_path);

    n = 0;
    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));

    if(bind(s, (struct sockaddr *)&addr, alen) < 0) {
        return  -1;
    }
    return s;
}

int socket_local_server(const char* name, int type) {
    int err;
    int s;

    s = socket(AF_LOCAL, type, 0);
    if(s < 0) return -1;

    err = socket_local_server_bind(s, name);

    if(err < 0) {
        close(s);
        return -1;
    }

    int ret = listen(s, LISTEN_BACKLOG);
    if(ret < 0) {
        close(s);
        return -1;
    }
    return s;
}

int socket_local_client_connect(int fd, const char* name) {
    struct sockaddr_un addr;
    socklen_t alen;
    int err;

    err = socket_make_sock_addr_un(name, &addr, &alen);

    if(err < 0) {
        return -1;
    }
    if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
        return -1;
    }

    return fd;
}

int socket_local_client(const char* name, int type) {
    int s;

    s = socket(AF_LOCAL, type, 0);

    if(s < 0) return -1;

    if(0 > socket_local_client_connect(s, name)) {
        close(s);

        return -1;
    }

    return s;
}